home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gscrdp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  19.7 KB  |  639 lines

  1. /* Copyright (C) 1998, 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gscrdp.c,v 1.2 2000/09/19 19:00:27 lpd Exp $ */
  20. /* CIE color rendering dictionary creation */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gsdevice.h"
  26. #include "gserrors.h"
  27. #include "gsmatrix.h"        /* for gscolor2.h */
  28. #include "gsstruct.h"
  29. #include "gxcspace.h"
  30. #include "gscolor2.h"        /* for gs_set/currentcolorrendering */
  31. #include "gscrdp.h"
  32. #include "gxarith.h"
  33.  
  34. /* ---------------- Writing ---------------- */
  35.  
  36. /* Internal procedures for writing parameter values. */
  37. private void
  38. store_vector3(float *p, const gs_vector3 * pvec)
  39. {
  40.     p[0] = pvec->u, p[1] = pvec->v, p[2] = pvec->w;
  41. }
  42. private int
  43. write_floats(gs_param_list * plist, gs_param_name key,
  44.          const float *values, int size, gs_memory_t * mem)
  45. {
  46.     float *p = (float *)
  47.     gs_alloc_byte_array(mem, size, sizeof(float), "write_floats");
  48.     gs_param_float_array fa;
  49.  
  50.     if (p == 0)
  51.     return_error(gs_error_VMerror);
  52.     memcpy(p, values, size * sizeof(float));
  53.  
  54.     fa.data = p;
  55.     fa.size = size;
  56.     fa.persistent = true;
  57.     return param_write_float_array(plist, key, &fa);
  58. }
  59. private int
  60. write_vector3(gs_param_list * plist, gs_param_name key,
  61.           const gs_vector3 * pvec, gs_memory_t * mem)
  62. {
  63.     float values[3];
  64.  
  65.     store_vector3(values, pvec);
  66.     return write_floats(plist, key, values, 3, mem);
  67. }
  68. private int
  69. write_matrix3(gs_param_list * plist, gs_param_name key,
  70.           const gs_matrix3 * pmat, gs_memory_t * mem)
  71. {
  72.     float values[9];
  73.  
  74.     if (!memcmp(pmat, &Matrix3_default, sizeof(*pmat)))
  75.     return 0;
  76.     store_vector3(values, &pmat->cu);
  77.     store_vector3(values + 3, &pmat->cv);
  78.     store_vector3(values + 6, &pmat->cw);
  79.     return write_floats(plist, key, values, 9, mem);
  80. }
  81. private int
  82. write_range3(gs_param_list * plist, gs_param_name key,
  83.          const gs_range3 * prange, gs_memory_t * mem)
  84. {
  85.     float values[6];
  86.  
  87.     if (!memcmp(prange, &Range3_default, sizeof(*prange)))
  88.     return 0;
  89.     values[0] = prange->ranges[0].rmin, values[1] = prange->ranges[0].rmax;
  90.     values[2] = prange->ranges[1].rmin, values[3] = prange->ranges[1].rmax;
  91.     values[4] = prange->ranges[2].rmin, values[5] = prange->ranges[2].rmax;
  92.     return write_floats(plist, key, values, 6, mem);
  93. }
  94. private int
  95. write_proc3(gs_param_list * plist, gs_param_name key,
  96.         const gs_cie_render * pcrd, const gs_cie_render_proc3 * procs,
  97.         const gs_range3 * domain, gs_memory_t * mem)
  98. {
  99.     float *values;
  100.     uint size = gx_cie_cache_size;
  101.     gs_param_float_array fa;
  102.     int i;
  103.  
  104.     if (!memcmp(procs, &Encode_default, sizeof(*procs)))
  105.     return 0;
  106.     values = (float *)gs_alloc_byte_array(mem, size * 3, sizeof(float),
  107.                       "write_proc3");
  108.  
  109.     if (values == 0)
  110.     return_error(gs_error_VMerror);
  111.     for (i = 0; i < 3; ++i) {
  112.     double base = domain->ranges[i].rmin;
  113.     double scale = (domain->ranges[i].rmax - base) / (size - 1);
  114.     int j;
  115.  
  116.     for (j = 0; j < size; ++j)
  117.         values[i * size + j] =
  118.         (*procs->procs[i]) (j * scale + base, pcrd);
  119.     }
  120.     fa.data = values;
  121.     fa.size = size * 3;
  122.     fa.persistent = true;
  123.     return param_write_float_array(plist, key, &fa);
  124. }
  125.  
  126. /* Write a CRD as a device parameter. */
  127. int
  128. param_write_cie_render1(gs_param_list * plist, gs_param_name key,
  129.             gs_cie_render * pcrd, gs_memory_t * mem)
  130. {
  131.     gs_param_dict dict;
  132.     int code, dcode;
  133.  
  134.     dict.size = 20;
  135.     if ((code = param_begin_write_dict(plist, key, &dict, false)) < 0)
  136.     return code;
  137.     code = param_put_cie_render1(dict.list, pcrd, mem);
  138.     dcode = param_end_write_dict(plist, key, &dict);
  139.     return (code < 0 ? code : dcode);
  140. }
  141.  
  142. /* Write a CRD directly to a parameter list. */
  143. int
  144. param_put_cie_render1(gs_param_list * plist, gs_cie_render * pcrd,
  145.               gs_memory_t * mem)
  146. {
  147.     int crd_type = GX_DEVICE_CRD1_TYPE;
  148.     int code = gs_cie_render_sample(pcrd); /* we need RenderTableT_is_id' */
  149.  
  150.     if (code < 0)
  151.     return code;
  152.     if (pcrd->TransformPQR.proc_name) {
  153.     gs_param_string pn, pd;
  154.  
  155.     param_string_from_string(pn, pcrd->TransformPQR.proc_name);
  156.     pn.size++;        /* include terminating null */
  157.     pd.data = pcrd->TransformPQR.proc_data.data;
  158.     pd.size = pcrd->TransformPQR.proc_data.size;
  159.     pd.persistent = true;  /****** WRONG ******/
  160.     if ((code = param_write_name(plist, "TransformPQRName", &pn)) < 0 ||
  161.         (code = param_write_string(plist, "TransformPQRData", &pd)) < 0
  162.         )
  163.         return code;
  164.     }
  165.     else if (pcrd->TransformPQR.proc != TransformPQR_default.proc) {
  166.     /* We have no way to represent the procedure, so return an error. */
  167.     return_error(gs_error_rangecheck);
  168.     }
  169.     if ((code = param_write_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
  170.     (code = write_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint, mem)) < 0
  171.     )
  172.     return code;
  173.     if (memcmp(&pcrd->points.BlackPoint, &BlackPoint_default,
  174.            sizeof(pcrd->points.BlackPoint))) {
  175.     if ((code = write_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint, mem)) < 0)
  176.         return code;
  177.     }
  178.     if ((code = write_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR, mem)) < 0 ||
  179.     (code = write_range3(plist, "RangePQR", &pcrd->RangePQR, mem)) < 0 ||
  180.     /* TransformPQR is handled separately */
  181.     (code = write_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN, mem)) < 0 ||
  182.     (code = write_proc3(plist, "EncodeLMNValues", pcrd,
  183.                 &pcrd->EncodeLMN, &pcrd->DomainLMN, mem)) < 0 ||
  184.     (code = write_range3(plist, "RangeLMN", &pcrd->RangeLMN, mem)) < 0 ||
  185.     (code = write_matrix3(plist, "MatrixABC", &pcrd->MatrixABC, mem)) < 0 ||
  186.     (code = write_proc3(plist, "EncodeABCValues", pcrd,
  187.                 &pcrd->EncodeABC, &pcrd->DomainABC, mem)) < 0 ||
  188.     (code = write_range3(plist, "RangeABC", &pcrd->RangeABC, mem)) < 0
  189.     )
  190.     return code;
  191.     if (pcrd->RenderTable.lookup.table) {
  192.     int n = pcrd->RenderTable.lookup.n;
  193.     int m = pcrd->RenderTable.lookup.m;
  194.     int na = pcrd->RenderTable.lookup.dims[0];
  195.     int *size = (int *)
  196.         gs_alloc_byte_array(mem, n + 1, sizeof(int), "RenderTableSize");
  197.  
  198.     /*
  199.      * In principle, we should use gs_alloc_struct_array with a
  200.      * type descriptor for gs_param_string.  However, it is widely
  201.      * assumed that parameter lists are transient, and don't require
  202.      * accurate GC information; so we can get away with allocating
  203.      * the string table as bytes.
  204.      */
  205.     gs_param_string *table =
  206.         (gs_param_string *)
  207.         gs_alloc_byte_array(mem, na, sizeof(gs_param_string),
  208.                 "RenderTableTable");
  209.     gs_param_int_array ia;
  210.  
  211.     if (size == 0 || table == 0)
  212.         code = gs_note_error(gs_error_VMerror);
  213.     else {
  214.         memcpy(size, pcrd->RenderTable.lookup.dims, sizeof(int) * n);
  215.  
  216.         size[n] = m;
  217.         ia.data = size;
  218.         ia.size = n + 1;
  219.         ia.persistent = true;
  220.         code = param_write_int_array(plist, "RenderTableSize", &ia);
  221.     }
  222.     if (code >= 0) {
  223.         gs_param_string_array sa;
  224.         int a;
  225.  
  226.         for (a = 0; a < na; ++a)
  227.         table[a].data = pcrd->RenderTable.lookup.table[a].data,
  228.             table[a].size = pcrd->RenderTable.lookup.table[a].size,
  229.             table[a].persistent = true;
  230.         sa.data = table;
  231.         sa.size = na;
  232.         sa.persistent = true;
  233.         code = param_write_string_array(plist, "RenderTableTable", &sa);
  234.         if (code >= 0 && !pcrd->caches.RenderTableT_is_identity) {
  235.         /****** WRITE RenderTableTValues LIKE write_proc3 ******/
  236.         uint size = gx_cie_cache_size;
  237.         float *values =
  238.             (float *)gs_alloc_byte_array(mem, size * m,
  239.                          sizeof(float),
  240.                          "write_proc3");
  241.         gs_param_float_array fa;
  242.         int i;
  243.  
  244.         if (values == 0)
  245.             return_error(gs_error_VMerror);
  246.         for (i = 0; i < m; ++i) {
  247.             double scale = 255.0 / (size - 1);
  248.             int j;
  249.  
  250.             for (j = 0; j < size; ++j)
  251.             values[i * size + j] =
  252.                 frac2float((*pcrd->RenderTable.T.procs[i])
  253.                        (j * scale, pcrd));
  254.         }
  255.         fa.data = values;
  256.         fa.size = size * m;
  257.         fa.persistent = true;
  258.         code = param_write_float_array(plist, "RenderTableTValues",
  259.                            &fa);
  260.         }
  261.     }
  262.     if (code < 0) {
  263.         gs_free_object(mem, table, "RenderTableTable");
  264.         gs_free_object(mem, size, "RenderTableSize");
  265.         return code;
  266.     }
  267.     }
  268.     return code;
  269. }
  270.  
  271. /* ---------------- Reading ---------------- */
  272.  
  273. /* Internal procedures for reading parameter values. */
  274. private void
  275. load_vector3(gs_vector3 * pvec, const float *p)
  276. {
  277.     pvec->u = p[0], pvec->v = p[1], pvec->w = p[2];
  278. }
  279. private int
  280. read_floats(gs_param_list * plist, gs_param_name key, float *values, int count)
  281. {
  282.     gs_param_float_array fa;
  283.     int code = param_read_float_array(plist, key, &fa);
  284.  
  285.     if (code)
  286.     return code;
  287.     if (fa.size != count)
  288.     return_error(gs_error_rangecheck);
  289.     memcpy(values, fa.data, sizeof(float) * count);
  290.  
  291.     return 0;
  292. }
  293. private int
  294. read_vector3(gs_param_list * plist, gs_param_name key,
  295.          gs_vector3 * pvec, const gs_vector3 * dflt)
  296. {
  297.     float values[3];
  298.     int code = read_floats(plist, key, values, 3);
  299.  
  300.     switch (code) {
  301.     case 1:        /* not defined */
  302.         if (dflt)
  303.         *pvec = *dflt;
  304.         break;
  305.     case 0:
  306.         load_vector3(pvec, values);
  307.     default:        /* error */
  308.         break;
  309.     }
  310.     return code;
  311. }
  312. private int
  313. read_matrix3(gs_param_list * plist, gs_param_name key, gs_matrix3 * pmat)
  314. {
  315.     float values[9];
  316.     int code = read_floats(plist, key, values, 9);
  317.  
  318.     switch (code) {
  319.     case 1:        /* not defined */
  320.         *pmat = Matrix3_default;
  321.         break;
  322.     case 0:
  323.         load_vector3(&pmat->cu, values);
  324.         load_vector3(&pmat->cv, values + 3);
  325.         load_vector3(&pmat->cw, values + 6);
  326.     default:        /* error */
  327.         break;
  328.     }
  329.     return code;
  330. }
  331. private int
  332. read_range3(gs_param_list * plist, gs_param_name key, gs_range3 * prange)
  333. {
  334.     float values[6];
  335.     int code = read_floats(plist, key, values, 6);
  336.  
  337.     switch (code) {
  338.     case 1:        /* not defined */
  339.         *prange = Range3_default;
  340.         break;
  341.     case 0:
  342.         prange->ranges[0].rmin = values[0];
  343.         prange->ranges[0].rmax = values[1];
  344.         prange->ranges[1].rmin = values[2];
  345.         prange->ranges[1].rmax = values[3];
  346.         prange->ranges[2].rmin = values[4];
  347.         prange->ranges[2].rmax = values[5];
  348.     default:        /* error */
  349.         break;
  350.     }
  351.     return code;
  352. }
  353. private int
  354. read_proc3(gs_param_list * plist, gs_param_name key,
  355.        float values[gx_cie_cache_size * 3])
  356. {
  357.     return read_floats(plist, key, values, gx_cie_cache_size * 3);
  358. }
  359.  
  360. /* Read a CRD from a device parameter. */
  361. int
  362. gs_cie_render1_param_initialize(gs_cie_render * pcrd, gs_param_list * plist,
  363.                 gs_param_name key, gx_device * dev)
  364. {
  365.     gs_param_dict dict;
  366.     int code = param_begin_read_dict(plist, key, &dict, false);
  367.     int dcode;
  368.  
  369.     if (code < 0)
  370.     return code;
  371.     code = param_get_cie_render1(pcrd, dict.list, dev);
  372.     dcode = param_end_read_dict(plist, key, &dict);
  373.     if (code < 0)
  374.     return code;
  375.     if (dcode < 0)
  376.     return dcode;
  377.     gs_cie_render_init(pcrd);
  378.     gs_cie_render_sample(pcrd);
  379.     return gs_cie_render_complete(pcrd);
  380. }
  381.  
  382. /* Define the structure for passing Encode values as "client data". */
  383. typedef struct encode_data_s {
  384.     float lmn[gx_cie_cache_size * 3]; /* EncodeLMN */
  385.     float abc[gx_cie_cache_size * 3]; /* EncodeABC */
  386.     float t[gx_cie_cache_size * 4]; /* RenderTable.T */
  387. } encode_data_t;
  388.  
  389. /* Define procedures that retrieve the Encode values read from the list. */
  390. private float
  391. encode_from_data(floatp v, const float values[gx_cie_cache_size],
  392.          const gs_range * range)
  393. {
  394.     return (v <= range->rmin ? values[0] :
  395.         v >= range->rmax ? values[gx_cie_cache_size - 1] :
  396.         values[(int)((v - range->rmin) / (range->rmax - range->rmin) *
  397.              (gx_cie_cache_size - 1) + 0.5)]);
  398. }
  399. /*
  400.  * The repetitive boilerplate in the next 10 procedures really sticks in
  401.  * my craw, but I've got a mandate not to use macros....
  402.  */
  403. private float
  404. encode_lmn_0_from_data(floatp v, const gs_cie_render * pcrd)
  405. {
  406.     const encode_data_t *data = pcrd->client_data;
  407.  
  408.     return encode_from_data(v, &data->lmn[0],
  409.                 &pcrd->DomainLMN.ranges[0]);
  410. }
  411. private float
  412. encode_lmn_1_from_data(floatp v, const gs_cie_render * pcrd)
  413. {
  414.     const encode_data_t *data = pcrd->client_data;
  415.  
  416.     return encode_from_data(v, &data->lmn[gx_cie_cache_size],
  417.                 &pcrd->DomainLMN.ranges[1]);
  418. }
  419. private float
  420. encode_lmn_2_from_data(floatp v, const gs_cie_render * pcrd)
  421. {
  422.     const encode_data_t *data = pcrd->client_data;
  423.  
  424.     return encode_from_data(v, &data->lmn[gx_cie_cache_size * 2],
  425.                 &pcrd->DomainLMN.ranges[2]);
  426. }
  427. private float
  428. encode_abc_0_from_data(floatp v, const gs_cie_render * pcrd)
  429. {
  430.     const encode_data_t *data = pcrd->client_data;
  431.  
  432.     return encode_from_data(v, &data->abc[0],
  433.                 &pcrd->DomainABC.ranges[0]);
  434. }
  435. private float
  436. encode_abc_1_from_data(floatp v, const gs_cie_render * pcrd)
  437. {
  438.     const encode_data_t *data = pcrd->client_data;
  439.  
  440.     return encode_from_data(v, &data->abc[gx_cie_cache_size],
  441.                 &pcrd->DomainABC.ranges[1]);
  442. }
  443. private float
  444. encode_abc_2_from_data(floatp v, const gs_cie_render * pcrd)
  445. {
  446.     const encode_data_t *data = pcrd->client_data;
  447.  
  448.     return encode_from_data(v, &data->abc[gx_cie_cache_size * 2],
  449.                 &pcrd->DomainABC.ranges[2]);
  450. }
  451. private frac
  452. render_table_t_0_from_data(byte v, const gs_cie_render * pcrd)
  453. {
  454.     const encode_data_t *data = pcrd->client_data;
  455.  
  456.     return float2frac(encode_from_data(v / 255.0,
  457.                        &data->t[0],
  458.                        &Range3_default.ranges[0]));
  459. }
  460. private frac
  461. render_table_t_1_from_data(byte v, const gs_cie_render * pcrd)
  462. {
  463.     const encode_data_t *data = pcrd->client_data;
  464.  
  465.     return float2frac(encode_from_data(v / 255.0,
  466.                        &data->t[gx_cie_cache_size],
  467.                        &Range3_default.ranges[0]));
  468. }
  469. private frac
  470. render_table_t_2_from_data(byte v, const gs_cie_render * pcrd)
  471. {
  472.     const encode_data_t *data = pcrd->client_data;
  473.  
  474.     return float2frac(encode_from_data(v / 255.0,
  475.                        &data->t[gx_cie_cache_size * 2],
  476.                        &Range3_default.ranges[0]));
  477. }
  478. private frac
  479. render_table_t_3_from_data(byte v, const gs_cie_render * pcrd)
  480. {
  481.     const encode_data_t *data = pcrd->client_data;
  482.  
  483.     return float2frac(encode_from_data(v / 255.0,
  484.                        &data->t[gx_cie_cache_size * 3],
  485.                        &Range3_default.ranges[0]));
  486. }
  487. private const gs_cie_render_proc3 EncodeLMN_from_data = {
  488.     {encode_lmn_0_from_data, encode_lmn_1_from_data, encode_lmn_2_from_data}
  489. };
  490. private const gs_cie_render_proc3 EncodeABC_from_data = {
  491.     {encode_abc_0_from_data, encode_abc_1_from_data, encode_abc_2_from_data}
  492. };
  493. private const gs_cie_render_table_procs RenderTableT_from_data = {
  494.     {render_table_t_0_from_data, render_table_t_1_from_data,
  495.      render_table_t_2_from_data, render_table_t_3_from_data
  496.     }
  497. };
  498.  
  499. /* Read a CRD directly from a parameter list. */
  500. int
  501. param_get_cie_render1(gs_cie_render * pcrd, gs_param_list * plist,
  502.               gx_device * dev)
  503. {
  504.     encode_data_t data;
  505.     gs_param_int_array rt_size;
  506.     int crd_type;
  507.     int code, code_lmn, code_abc, code_rt, code_t;
  508.     gs_param_string pname, pdata;
  509.  
  510.     /* Reset the status to invalidate cached information. */
  511.     pcrd->status = CIE_RENDER_STATUS_BUILT;
  512.     if ((code = param_read_int(plist, "ColorRenderingType", &crd_type)) < 0 ||
  513.     crd_type != GX_DEVICE_CRD1_TYPE ||
  514.     (code = read_vector3(plist, "WhitePoint", &pcrd->points.WhitePoint,
  515.                  NULL)) < 0 ||
  516.     (code = read_vector3(plist, "BlackPoint", &pcrd->points.BlackPoint,
  517.                  &BlackPoint_default)) < 0 ||
  518.     (code = read_matrix3(plist, "MatrixPQR", &pcrd->MatrixPQR)) < 0 ||
  519.     (code = read_range3(plist, "RangePQR", &pcrd->RangePQR)) < 0 ||
  520.     /* TransformPQR is handled specially below. */
  521.     (code = read_matrix3(plist, "MatrixLMN", &pcrd->MatrixLMN)) < 0 ||
  522.     (code_lmn = code =
  523.      read_proc3(plist, "EncodeLMNValues", data.lmn)) < 0 ||
  524.     (code = read_range3(plist, "RangeLMN", &pcrd->RangeLMN)) < 0 ||
  525.     (code = read_matrix3(plist, "MatrixABC", &pcrd->MatrixABC)) < 0 ||
  526.     (code_abc = code =
  527.      read_proc3(plist, "EncodeABCValues", data.abc)) < 0 ||
  528.     (code = read_range3(plist, "RangeABC", &pcrd->RangeABC)) < 0
  529.     )
  530.     return code;
  531.     /* Handle the sampled functions. */
  532.     switch (code = param_read_string(plist, "TransformPQRName", &pname)) {
  533.     default:        /* error */
  534.         return code;
  535.     case 1:            /* missing */
  536.         pcrd->TransformPQR = TransformPQR_default;
  537.         break;
  538.     case 0:            /* specified */
  539.         /* The procedure name must be null-terminated: */
  540.         /* see param_put_cie_render1 above. */
  541.         if (pname.size < 1 || pname.data[pname.size - 1] != 0)
  542.         return_error(gs_error_rangecheck);
  543.         pcrd->TransformPQR.proc = TransformPQR_lookup_proc_name;
  544.         pcrd->TransformPQR.proc_name = (char *)pname.data;
  545.         switch (code = param_read_string(plist, "TransformPQRData", &pdata)) {
  546.         default:    /* error */
  547.             return code;
  548.         case 1:        /* missing */
  549.             pcrd->TransformPQR.proc_data.data = 0;
  550.             pcrd->TransformPQR.proc_data.size = 0;
  551.             break;
  552.         case 0:
  553.             pcrd->TransformPQR.proc_data.data = pdata.data;
  554.             pcrd->TransformPQR.proc_data.size = pdata.size;
  555.         }
  556.         pcrd->TransformPQR.driver_name = gs_devicename(dev);
  557.         break;
  558.     }
  559.     pcrd->client_data = &data;
  560.     if (code_lmn > 0)
  561.     pcrd->EncodeLMN = Encode_default;
  562.     else
  563.     pcrd->EncodeLMN = EncodeLMN_from_data;
  564.     if (code_abc > 0)
  565.     pcrd->EncodeABC = Encode_default;
  566.     else
  567.     pcrd->EncodeABC = EncodeABC_from_data;
  568.     code_rt = code = param_read_int_array(plist, "RenderTableSize", &rt_size);
  569.     if (code == 1) {
  570.     if (pcrd->RenderTable.lookup.table) {
  571.         gs_free_object(pcrd->rc.memory,
  572.         (void *)pcrd->RenderTable.lookup.table, /* break const */
  573.         "param_get_cie_render1(RenderTable)");
  574.         pcrd->RenderTable.lookup.table = 0;
  575.     }
  576.     pcrd->RenderTable.T = RenderTableT_default;
  577.     code_t = 1;
  578.     } else if (code < 0)
  579.     return code;
  580.     else if (rt_size.size != 4)
  581.     return_error(gs_error_rangecheck);
  582.     else {
  583.     gs_param_string_array rt_values;
  584.     gs_const_string *table;
  585.     int n, m, j;
  586.  
  587.     for (j = 0; j < rt_size.size; ++j)
  588.         if (rt_size.data[j] < 1)
  589.         return_error(gs_error_rangecheck);
  590.     code = param_read_string_array(plist, "RenderTableTable", &rt_values);
  591.     if (code < 0)
  592.         return code;
  593.     if (code > 0 || rt_values.size != rt_size.data[0])
  594.         return_error(gs_error_rangecheck);
  595.     /* Note: currently n = 3 (rt_size.size = 4) always. */
  596.     for (j = 0; j < rt_values.size; ++j)
  597.         if (rt_values.data[j].size !=
  598.         rt_size.data[1] * rt_size.data[2] * rt_size.data[3])
  599.         return_error(gs_error_rangecheck);
  600.     pcrd->RenderTable.lookup.n = n = rt_size.size - 1;
  601.     pcrd->RenderTable.lookup.m = m = rt_size.data[n];
  602.     if (n > 4 || m > 4)
  603.         return_error(gs_error_rangecheck);
  604.     memcpy(pcrd->RenderTable.lookup.dims, rt_size.data, n * sizeof(int));
  605.     table =
  606.         gs_alloc_struct_array(pcrd->rc.memory,
  607.                   pcrd->RenderTable.lookup.dims[0],
  608.                   gs_const_string, &st_const_string_element,
  609.                   "RenderTable table");
  610.     if (table == 0)
  611.         return_error(gs_error_VMerror);
  612.     for (j = 0; j < pcrd->RenderTable.lookup.dims[0]; ++j) {
  613.         table[j].data = rt_values.data[j].data;
  614.         table[j].size = rt_values.data[j].size;
  615.     }
  616.     pcrd->RenderTable.lookup.table = table;
  617.     pcrd->RenderTable.T = RenderTableT_from_data;
  618.     code_t = code = read_floats(plist, "RenderTableTValues", data.t,
  619.                     gx_cie_cache_size * m);
  620.     if (code > 0)
  621.         pcrd->RenderTable.T = RenderTableT_default;
  622.     else if (code == 0)
  623.         pcrd->RenderTable.T = RenderTableT_from_data;
  624.     }
  625.     if ((code = gs_cie_render_init(pcrd)) >= 0 &&
  626.     (code = gs_cie_render_sample(pcrd)) >= 0
  627.     )
  628.     code = gs_cie_render_complete(pcrd);
  629.     /* Clean up before exiting. */
  630.     pcrd->client_data = 0;
  631.     if (code_lmn == 0)
  632.     pcrd->EncodeLMN = EncodeLMN_from_cache;
  633.     if (code_abc == 0)
  634.     pcrd->EncodeABC = EncodeABC_from_cache;
  635.     if (code_t == 0)
  636.     pcrd->RenderTable.T = RenderTableT_from_cache;
  637.     return code;
  638. }
  639.